﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using CompilationFactures.Enums;
using System.Xml;
using System.Windows.Forms;
using System.Xml.Linq;

namespace CompilationFactures.Objects
{
    public abstract class Facture : IArticle
    {
        protected Facture()
        {
            AttribuerNumero();
        }

        public void AttribuerNumero()
        {
            int numero = 1;
            if (DictionnaireDonnees.ListeFacture.Count > 0)
            {
                numero = DictionnaireDonnees.ListeFacture.Max(fact => fact.NoFacture) + 1;
            }
            noFacture = numero;
        }

        protected Facture(int _NoFacture, List<Article> _Articles)
        {
            noFacture = _NoFacture;

            listeArticles = _Articles;

            operation = Operation.Aucune;
        }

        protected int noFacture;
        protected FileInfo fichierSauvegarde;
        protected List<Article> listeArticles;
        protected Operation operation;

        abstract public string DescriptionType
        {
            get;
        }

        abstract public string Type
        {
            get;
        }

        public int NoFacture
        {
            get
            {
                return noFacture;
            }
        }

        public FileInfo FichierSauvegarde
        {
            get
            {
                return fichierSauvegarde;
            }
            set
            {
                fichierSauvegarde = value;
            }
        }

        public List<Article> ListeArticles
        {
            get
            {
                if (listeArticles == null)
                {
                    listeArticles = new List<Article>();
                }
                return listeArticles;
            }
            set
            {
                listeArticles = value;
            }
        }

        public decimal SousTotal
        {
            get
            {
                return ListeArticles.Sum(art => art.SousTotal);
            }
        }

        public decimal TPS
        {
            get
            {
                return ListeArticles.Sum(art => art.TPS);
            }
        }

        public decimal TVQ
        {
            get
            {
                return ListeArticles.Sum(art => art.TVQ);
            }
        }

        public decimal Total
        {
            get
            {
                return ListeArticles.Sum(art => art.Total);
            }
        }

        public Operation Operation
        {
            get 
            {
                return operation;
            }
            set
            {
                operation = value;
            }
        }

        public abstract Facture Copier();

        public List<Article> copierArticles()
        {
            List<Article> listeArticles = new List<Article>();
            foreach (Article art in this.ListeArticles)
            {
                listeArticles.Add(new Article(art));
            }
            return listeArticles;
        }

        public void Enregistrer(string path)
        {
            try
            {
                if (File.Exists(path))
                    File.Delete(path);

                XDocument objXDoc = new XDocument(
                    new XComment("Informations d'une facture"),
                    new XElement("Facture",
                                            new XElement("Type", Type),
                                            new XElement("Numero", noFacture),
                                            new XElement("Articles", ListeArticles.Select(art => new XElement("Article", 
                                                                                            new XElement("Item", art.Item),
                                                                                            new XElement("Prix", art.Prix.ToString().Replace(".", ",")),
                                                                                            new XElement("Quantite", art.Quantite),
                                                                                            new XElement("Taxe", art.Taxe)
                                                                                          )
                            )
                        )
                    )
                );

                objXDoc.Declaration = new XDeclaration("1.0", "utf-8", "true");
                
                objXDoc.Save(path);
                
            }
            catch (Exception e)
            {
                MessageBox.Show("Une erreur est survenue lors de la création du fichier " + path + ";" + e.Message, "Attention", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        static public Facture ChargerFichier(string path)
        {
            try
            {
                XElement facture = XElement.Load(path);

                string type = facture.Element("Type").Value;
                int noFacture = Convert.ToInt32(facture.Element("Numero").Value);

                IEnumerable<XElement> xmlArticles = facture.Element("Articles").Elements();

                List<Article> articles = new List<Article>();

                foreach (XElement art in xmlArticles)
                {
                    articles.Add(new Article(art.Element("Item").Value,
                                             Convert.ToDecimal(art.Element("Prix").Value.Replace(".", ",")),
                                             Convert.ToInt32(art.Element("Quantite").Value),
                                             (EnumTaxes)Enum.Parse(typeof(EnumTaxes), art.Element("Taxe").Value))
                                );
                }

                Facture nouvelleFacture;

                if (DictionnaireDonnees.ListeFacture.Exists(fact => fact.noFacture.Equals(noFacture)))
                {
                    MessageBox.Show("Une facture ayant ce numéro existe déja dans le système; un nouveau numéro sera attribué à la facture que vous chargez.");
                    noFacture = DictionnaireDonnees.ListeFacture.Max(fact => fact.NoFacture) + 1;
                }

                switch (type)
                {
                    case "Épicerie": nouvelleFacture = new FactureEpicerie(noFacture, articles);
                    break;

                    case "Garage": nouvelleFacture = new FactureGarage(noFacture, articles);
                    break;

                    default: nouvelleFacture = null;
                    break;
                }

                return nouvelleFacture;
            }
            catch (Exception e)
            {
                MessageBox.Show("Une erreur est survenue lors du chargement de la facture; " + e.Message, "Attention", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return null;
            }
        }

        #region IArticle Membres

        public Article CreerArticle(string item, decimal prix, int quantite, EnumTaxes taxe)
        {
            Article art = new Article(item, prix, quantite, taxe);
            ListeArticles.Add(art);
            return art;
        }

        public void AjouterArticle(Article art)
        {
            Article articleTrouve = listeArticles.Find(article => article.Item.Equals(art.Item));
            if (articleTrouve != null)
            {
                articleTrouve.Taxe = art.Taxe;
                articleTrouve.Prix = art.Prix;
                articleTrouve.Quantite += art.Quantite;
                if (articleTrouve.Quantite < 1)
                {
                    listeArticles.Remove(articleTrouve);
                }
            }
            else
            {
                if (!(art.Quantite < 1))
                {
                    ListeArticles.Add(art);
                }
            }
            
        }

        public void RetirerArticle(string item)
        {
            ListeArticles.RemoveAll(art => art.Item.Equals(item));
        }

        public int NbArticles()
        {
            return ListeArticles.Sum(art => art.Quantite);
        }

        private static void CreerFichier(string nomFichier)
        {
            try
            {
                if (!File.Exists(nomFichier))
                {

                    XmlDocument doc = new XmlDocument();

                    XmlDeclaration declaration = doc.CreateXmlDeclaration("1.0", "utf-8", null);

                    XmlElement root = doc.CreateElement("Facture");
                    doc.InsertBefore(declaration, doc.DocumentElement);
                    doc.AppendChild(root);

                    doc.Save(nomFichier);
                }
            }
            catch (Exception e)
            {
                MessageBox.Show("Une erreur est survenue lors de la création du fichier " + nomFichier + ";" + e.Message, "Attention", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        #endregion

        public override string ToString()
        {
            return String.Format("Facture {0}", this.NoFacture);
        }

        public void ToNegative()
        {
            foreach (Article art in listeArticles)
            {
                art.Quantite = art.Quantite * -1;
            }
        }
    }
}
